#include <autoconfig.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>

#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <stdio.h>

#include "proginfo.h"
// #include "fpga-tr700.h"
#include "printl.h"

#include "pthread.h"
// #include "fpga-otdr-cfg.h"
// #include "fpga_encode.h"


#include "port.h"
#include "fpga-common.h"
#include "interface/protocal-otdr.h"

#include "encode-otdr.h"

extern int env_ignore_rx;

// Fix LS2K unsupport cs unchange
#define CONFIG_READ_1000_POINT (0)

#define SPI_TP_BEGIN           _IOR(SPI_IOC_MAGIC, 5, __u8)
#define SPI_TP_COMMIT          _IOR(SPI_IOC_MAGIC, 6, __u8)

#define this_dbg(fmt, ...)                                           \
    if (env_otdr_dbg_level) {                                        \
	PRINTL(OTDR_DBG_LEVEL, C_DEBUG fmt C_NORMAL, ##__VA_ARGS__); \
    }

// #define this_dbg(fmt, ...)

#if defined(CONFIG_USE_DEBUG_ENV)
#define ENV_PRINT_E(fmt, ...)                              \
    if (env_print_e) {                                     \
	_ctstprint(C_ERROR, C_NORMAL, fmt, ##__VA_ARGS__); \
    }
#define ENV_PRINT_W(fmt, ...)                             \
    if (env_print_w) {                                    \
	_ctstprint(C_WARN, C_NORMAL, fmt, ##__VA_ARGS__); \
    }
#else
#define ENV_PRINT_E(fmt, ...)
#define ENV_PRINT_w(fmt, ...)
#endif


// 这个是默认的数据结构
struct otdr_driver_data_tr700
{
    char	 *otdr_cache;
    unsigned char ch;
    unsigned long checksum;  ///< OTDR
    int           cache_len;
};

static inline char *get_cache(struct fpga_dev *dev)
{
    struct otdr_driver_data_tr700 *p = (struct otdr_driver_data_tr700 *)fpga_if_get_driver_data(dev->interface);
    return p->otdr_cache;
}

static inline char *get_cache_len(struct fpga_dev *dev)
{
    struct otdr_driver_data_tr700 *p = (struct otdr_driver_data_tr700 *)fpga_if_get_driver_data(dev->interface);
    return p->cache_len;
}

#if 0  // 老版本
static int _fpga_otdr_start(struct fpga_dev *dev)
{
	assert(dev != NULL);
	assert(dev->desc == dev_desc);

	char rbuf[MIN_RX_PACK_SIZE];
	int retry = 0;

_again:
	_fpga_transfer(dev,
		       OTDR_START,
		       &dev->ch,
		       sizeof(dev->ch),
		       rbuf,
		       ARRAY_SIZE(rbuf));

	unsigned char ack;
	int offset = 0;
_CheckFrame:;
	ack = ACK_CODE(rbuf + offset);
	retry++;
	switch (ack) {
	case 0xaa:
		this_dbg("%s() OK\r\n", __FUNCTION__);
		return 0;
	case 0x55:
		ENV_PRINT_W("Error\r\n");
		return -1;
	default:
		offset = _find_frame_start(rbuf, ARRAY_SIZE(rbuf) / 2);
		if (retry < RETRY || -1 == offset) {
			ENV_PRINT_E("unknow\r\n");
			offset = 0;
			break;
		}
		else {
			goto _CheckFrame;
		}
		break;
	}

	if (retry < RETRY) {
		goto _again;
	}
	ENV_PRINT_E("retry time out\r\n");
	return -1;
}

int fpga_otdr_start(struct fpga_dev *dev)
{
    do_otdr_test_led(1);
	mutex_lock(&dev->mutex);
	int ret = _fpga_otdr_start(dev);
	mutex_unlock(&dev->mutex);
	return ret;
}

#else
/*
为了兼容，请用 fpga_if_start 代替
*/
struct otdr_start
{
    char ch;
};

int cb_fpga_otdr_start(struct fpga_dev *dev)
{
    fpga_if_set_gpio(dev, IO_OTDR_ON_TEST, 1);

    struct otdr_start tbuf;
    char              rbuf[MIN_RX_PACK_SIZE];
    tbuf.ch = dev->ch;

    int ret = fpga_send_data(dev,
                             OTDR_START,
                             &tbuf,
                             sizeof(struct otdr_start),
                             rbuf,
                             sizeof(rbuf));
    return ret;
}

#endif
#if 0  // 老版本
int fpga_otdr_stop(struct fpga_dev *dev)
{
	printf("\r\n\r\ndsfd\r\n");
	sleep(1);
	assert(dev != NULL);
	assert(dev->desc == dev_desc);

	char rbuf[MIN_RX_PACK_SIZE];

    do_otdr_test_led(0);
	mutex_lock(&dev->mutex);
	_fpga_transfer(dev, OTDR_STOP,
	               &dev->ch, sizeof(dev->ch),
	               rbuf, ARRAY_SIZE(rbuf) );
	mutex_unlock(&dev->mutex);

	unsigned char ack = ACK_CODE(rbuf);
	switch (ack) {
	case 0xaa:
		this_dbg("%s() OK\r\n", __FUNCTION__);
		return 0;
	case 0x55:
		ENV_PRINT_W("Error\r\n");
		return -1;
	default:
		ENV_PRINT_E("unknow\r\n");
		return -1;
	}
	return -1;
}
#else
/*
为了兼容，请用 fpga_if_stop 代替
*/
struct otdr_stop
{
    char ch;
};
int cb_fpga_otdr_stop(struct fpga_dev *dev)
{
    fpga_if_set_gpio(dev, IO_OTDR_ON_TEST, 0);

    struct otdr_stop tbuf;
    char             rbuf[MIN_RX_PACK_SIZE];
    tbuf.ch = dev->ch;

    return fpga_send_data(dev,
                          OTDR_STOP,
                          &tbuf,
                          sizeof(struct otdr_stop),
                          rbuf,
                          sizeof(rbuf));
}
#endif

#if 0
int _fpga_otdr_isfinish(struct fpga_dev *dev, bool *val)
{
	assert(dev != NULL);
	assert(dev->desc == dev_desc);

	char rbuf[MIN_RX_PACK_SIZE];

	mutex_lock(&dev->mutex);
	_fpga_transfer(dev,
		       OTDR_IS_FINISH,
		       &dev->ch,
		       sizeof(dev->ch),
		       rbuf,
		       ARRAY_SIZE(rbuf));
	mutex_unlock(&dev->mutex);

	unsigned char ack;
	int offset = 0;
	int retry  = 0;

	*val = false;
_CheckFrame:;
	ack = ACK_CODE(rbuf + offset);
	retry++;
	switch (ack) {
	case 0xaa:
		dev->checksum  = _STREAM_TO_32(&rbuf[CHKSUM_OFFSET]);
		dev->cum_count = _STREAM_TO_16(&rbuf[CUM_COUNT_OFFSET]);
		*val	       = true;
		printf("------------true\r\n");
		return 0;
	case 0x55:
		dev->checksum  = 0;
		dev->cum_count = 0;
		*val	       = false;
		printf("------------false\r\n");
		ENV_PRINT_E("Error\r\n");
		return 0;
	default:
		offset = _find_frame_start(rbuf, ARRAY_SIZE(rbuf) / 2);
		if (retry < RETRY || -1 == offset) {
#if defined(CONFIG_OTDR_PRINT_RX) && defined(CONFIG_ISFINISH_RX)
			PrintfMemory((uint8_t *)rbuf, ARRAY_SIZE(rbuf));
			ENV_PRINT_E("unknow\r\n");
#endif
			offset = 0;
			printf("------------default\r\n");
			return -1;
		}
		else {
			goto _CheckFrame;
		}
	}
	return -1;
}
int fpga_otdr_isfinish(struct fpga_dev *dev, bool *val)
{
	return fpga_if_isfinish(dev, val);
}
#else
// TODO 更改
int cb_fpga_otdr_isfinish(struct fpga_dev *dev, bool *val)
{
    unsigned char     ack;
    struct otdr_start tbuf;
    char              rbuf[MIN_RX_PACK_SIZE];
    tbuf.ch = dev->ch;

    fpga_send_data(dev,
                   OTDR_IS_FINISH,
                   &tbuf,
                   sizeof(struct otdr_start),
                   rbuf,
                   sizeof(rbuf));
    ack = ACK_CODE(rbuf);
    if (env_ignore_rx) {
	ack = 0xaa;
    }
    switch (ack) {
    case 0xaa:
	dev->checksum  = _STREAM_TO_32(&rbuf[CHKSUM_OFFSET]);
	dev->cum_count = _STREAM_TO_16(&rbuf[CUM_COUNT_OFFSET]);
	*val           = true;
	return 0;
    case 0x55:
	dev->checksum  = 0;
	dev->cum_count = 0;
	*val           = false;
	ENV_PRINT_E("Error\r\n");
	return 0;
    default:
	return -1;
    }
}

#endif


// TODO 需要把 _read_otdr_serial设置成非 static


static int _otdr_data_swap(unsigned char *buf, int len)
{
    unsigned char *pchar = (unsigned char *)buf;
    char           tmp[4];


    for (int i = 0; i < len;) {
#if defined(CONFIG_CHK_OTDR_FLAG)
	if (pchar[0] != DATA_FLAG) {
	    ENV_PRINT_E("error otdr data index %i\n", i);
	    printf("error otdr data index %i\n", i);
	    // debug
	    if (i >= 100) {
		printf("Before 100 byte:\r\n");
		PrintfMemory((uint8_t *)pchar - 100, 100);
	    }
	    if (i < len - 100) {
		printf("After 100 byte:\r\n");
		PrintfMemory((uint8_t *)pchar, 100);
	    }
	    // End debug
	    return -1;
	}
#endif
	tmp[0] = pchar[0];
	tmp[1] = pchar[1];
	tmp[2] = pchar[2];
	tmp[3] = pchar[3];

	pchar[3] = 0;
	pchar[2] = tmp[1];
	pchar[1] = tmp[2];
	pchar[0] = tmp[3];

	pchar += 4;
	i += 4;
    }
    return 0;
}

/**
 * @brief	计算连续数据校验和，数据必须是4byte
 倍数，数据已4byte为单位相加。 如:\n 0x01 0x02 0x03 0x04 0x05 0x06 0x07 0x08
    chksum = 0x04030201 + 0x08070605
 * @param	data 待计算数据
 * @param	len 数据长度，必须是4byte倍数
 * @retval 校验值
 * @see	_otdr_checksum
 */
// static
unsigned long __checksum(unsigned char *data, int len)
{
    unsigned int *plong;
    unsigned int  loop = len >> 2;
    unsigned int  sum  = 0, tmp;

    plong = (unsigned int *)data;

    for (int i = 0; i < loop; i++) {
	tmp = (unsigned int)data[0] + (unsigned int)(data[1] << 8) +
	      (unsigned int)(data[2] << 16) +
	      (unsigned int)(data[3] << 24);
	sum += *plong++;
    }

    return sum;
}
/*
本函数是整个通信效率最慢的：
1. 2次拷贝：spi 控制器 --->  内部otdr_cache ---> 用户otdr_data
2. 数据交换：高低字节对调 _otdr_data_swap，
打算接收数据0x00aabbcc，FPGA实际发送的是 0x23 0xXX 0xXX
0xXX，至于顺序是什么我不想管
3. 很多对FPGA传输的纠错处理
*/
int cb_fpga_read_otdr_data(
	struct fpga_dev *dev,
	unsigned char   *otdr_data,
	unsigned long    len,
	unsigned long   *rlen)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    // assert(dev->otdr_cache != NULL);
    assert(len == 16000 * 4 || len == 32000 * 4 || len == 64000 * 4 ||
           len == 128000 * 4);

    // char *rbuf = dev->otdr_cache;
    // struct otdr_driver_data_tr700 *p = (struct otdr_driver_data_tr700 *)fpga_if_get_driver_data(dev->interface);
    // char *rbuf  = p->otdr_cache;
    char *rbuf = get_cache(dev);
    // char *rbuf = otdr_data;
    /*
     * OTDR 数据格式，第一个0x23开头，后面每 4 byte为1数据点，每数据点
     * 0x23开头 0x23 | 0x23 xx xx xx | 0x23 xx xx xx | 0x23 xx xx xx
     *
     *         otdr_cache 最终存储的内容
     * |    0 byte             32000*4| 4000 |
     * |    OTDR 数据                 | 冗余 |
     * 后面的冗余内容是为了处理OTDR数据偏移而特意多读的
     */
    // do_otdr_test_led(0);
    fpga_if_set_gpio(dev, IO_OTDR_ON_TEST, 0);


    int find_23 = 0;
    this_dbg("%s() search 'DATA_FLAG' \r\n", __FUNCTION__);

    /*
    步骤1：请求数据
    FPGA有BUG，经常返回内容格式“错位”
    本步骤除了_fpga_transfer外，其他都是为了调试查错的
    */
    // 逐个寻找标志字符，
    mutex_lock(&dev->mutex);
    // 这个for循环可以从3改成1
    for (int j = 0; j < 3; j++) {
	/*
	 * 发送请求，这个不能少，只读取 1byte，寻找标志
	 */
	_fpga_transfer(dev,
	               OTDR_ROTDR,
	               &dev->ch,
	               sizeof(dev->ch),
	               //    dev->otdr_cache,
	               get_cache(dev),
	               1);
	/*
	逐个byte读取，在一定范围内寻找otdr数据帧头，
	找到后就连快速读取后面的数据
	*/
#define CHECK_SERIAL (30)  // 在数据头N个字节里寻找标志

	for (int i = 0; i < CHECK_SERIAL; i++) {
	    //            printf("%s() %d\r\n", __FUNCTION__,
	    //            __LINE__);

	    // if (dev->otdr_cache[0] == DATA_FLAG) {
	    if (get_cache(dev)[0] == DATA_FLAG) {
		find_23 = 1;
		goto _SerialRead;
	    }
	    // _read_otdr_1(
	    // 		dev,
	    // 		(unsigned char *)(dev->otdr_cache),
	    // 		1);

	    _read_otdr_1(
		    dev,
		    (unsigned char *)(get_cache(dev)),
		    1);
	}
    }

_SerialRead:;
    if (find_23 == 0) {
	ENV_PRINT_E(
		"otdr data errr: can't find flag 'DATA_FLAG' (0-100 byte) %2.2x %2.2x %2.2x %2.2x\r\n",
		*(get_cache(dev) + 0),
		*(get_cache(dev) + 1),
		*(get_cache(dev) + 2),
		*(get_cache(dev) + 3));
	mutex_unlock(&dev->mutex);
	return -1;
    }


    /*
    步骤2：读取后面的所有数据
    FPGA数据发送计数器未清0，可能导致不响应之后的数据，解决方法：
    1、otdr_cache长度最好远大于FPGA返回长度，保证把FPGA读空，后面的数据是全0x00或0xff。
    2、每次和FPGA握手时首先度全远大于FPGA返回长度；
    目前只使用方案1，方案2只是验证FPGA有错误。
    后来FPGA做了修改，在每次收到OTDR_START请求后清空计数器；最好的做法是CS上身边沿清除
    */

    // Fix LS2K: 不支持 cs_change = 0,所以必须一次性读取所有数据
    // _read_otdr_serial(dev, (unsigned char *)(dev->otdr_cache), len, 0);
    _read_otdr_serial(dev, (unsigned char *)(get_cache(dev)), len, 0);


    if (env_dbg_rx) {
	this_dbg("%s() peek receive data", __FUNCTION__);
	PrintfMemory((uint8_t *)rbuf, 16);
    }

    // 拷贝到调用者
    memcpy_char((char *)otdr_data, (char *)(rbuf + 0), len);
    mutex_unlock(&dev->mutex);


    /*
    数据都在 otdr_data 里，下面的数据double otdr_cache 的锁不再有效
    整个系统最慢的地方就在这里，对数据交换、高Byte清0
    */
    __attribute__((unused)) int swap_err = _otdr_data_swap(otdr_data, len);
    // _print_otdr_data((unsigned long *)otdr_data, len / 4);
    brief_print_data((unsigned long *)otdr_data, len / 4);

    extern int env_save_otdr;
    if (env_save_otdr) {
	fpga_save_32bit("/tmp/a-otdr.csv", otdr_data, len);
    }
#if defined(CONFIG_CHK_OTDR_FLAG) && !defined(CONFIG_USE_CKSUM)
    if (swap_err == -1) {
	return -1;
    }
    return 0;
#else
    if (swap_err == -1) {
	printf("otdr swap error\r\n");
	return -1;
    }
    unsigned long sum = 0;
    if (env_unuse_cksum == 0) {
	sum = __checksum(otdr_data, len);
	if ((unsigned int)(dev->checksum & 0xffffffff) ==
	    (unsigned int)(sum & 0xffffffff))
	{
	    this_dbg("%s() check sum OK\r\n", __FUNCTION__);
	    return 0;
	}
	else {
	    ENV_PRINT_W("check sum error cksum [%lx] otdr [%lx]\n",
	                (long)(dev->checksum),
	                (long)(sum));
	    return -1;
	}
    }
    else {
	// printf("env_unuse_cksum = 1\r\n");
	return 0;
    }
#endif
}

int cb_fpga_read_otdr_data_orangepi(
	struct fpga_dev *dev,
	unsigned char   *otdr_data,
	unsigned long    len,
	unsigned long   *rlen)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    // assert(dev->otdr_cache != NULL);
    assert(len == 16000 * 4 || len == 32000 * 4 || len == 64000 * 4 ||
           len == 128000 * 4);

    // char *rbuf = dev->otdr_cache;
    // struct otdr_driver_data_tr700 *p = (struct otdr_driver_data_tr700 *)fpga_if_get_driver_data(dev->interface);
    // char *rbuf  = p->otdr_cache;
    char *rbuf = get_cache(dev);
    // char *rbuf = otdr_data;
    /*
     * OTDR 数据格式，第一个0x23开头，后面每 4 byte为1数据点，每数据点
     * 0x23开头 0x23 | 0x23 xx xx xx | 0x23 xx xx xx | 0x23 xx xx xx
     *
     *         otdr_cache 最终存储的内容
     * |    0 byte             32000*4| 4000 |
     * |    OTDR 数据                 | 冗余 |
     * 后面的冗余内容是为了处理OTDR数据偏移而特意多读的
     */
    // do_otdr_test_led(0);
    fpga_if_set_gpio(dev, IO_OTDR_ON_TEST, 0);


    int find_23 = 0;
    this_dbg("%s() search 'DATA_FLAG' \r\n", __FUNCTION__);

    /*
    步骤1：请求数据
    FPGA有BUG，经常返回内容格式“错位”
    本步骤除了_fpga_transfer外，其他都是为了调试查错的
    */
    // 逐个寻找标志字符，
    mutex_lock(&dev->mutex);
    // 这个for循环可以从3改成1

    for (int j = 0; j < 1; j++) {
	/*
	 * 发送请求，这个不能少，只读取 1byte，寻找标志
	 */
	_fpga_transfer(dev,
	               OTDR_ROTDR,
	               &dev->ch,
	               sizeof(dev->ch),
	               //    dev->otdr_cache,
	               get_cache(dev),
	               4);
	printf("i = %d-----------------\r", 2222);
	// printf("len %d--------\r\n", len);
	// for (int k = 0; k < len;) {
	// 	printf("i = %d\r\n", k);
	// 	_read_otdr_serial(dev, (unsigned char *)(get_cache(dev)+ 4 + k), 4000, 0);
	// 	k += 4000;// 读取1000个点
	// }
	// _read_otdr_serial(dev, (unsigned char *)(get_cache(dev) + 4 + 4000 * 0), 4000*2, 0);
	// _read_otdr_serial(dev, (unsigned char *)(get_cache(dev) + 4 + 4000 * 2), 4000*2, 0);

	_read_otdr_serial(dev, (unsigned char *)(get_cache(dev) + 4 + 32000 * 0), 32000 * 2, 0);
	_read_otdr_serial(dev, (unsigned char *)(get_cache(dev) + 4 + 32000 * 2), 32000 * 2, 0);
	// _read_otdr_serial(dev, (unsigned char *)(get_cache(dev) + 4 + 32000 * 2), 32000, 0);
	// _read_otdr_serial(dev, (unsigned char *)(get_cache(dev) + 4 + 32000 * 3), 32000, 0);


	// printf("len %d\r\n", len);
	// brief_print_data((unsigned long *)get_cache(dev), len / 8);
	// PrintfMemory((uint8_t *)get_cache(dev), 32000);
	/*
	逐个byte读取，在一定范围内寻找otdr数据帧头，
	找到后就连快速读取后面的数据
	*/
	goto _SerialRead;
#define CHECK_SERIAL (30)  // 在数据头N个字节里寻找标志

	for (int i = 0; i < CHECK_SERIAL; i++) {
	    //            printf("%s() %d\r\n", __FUNCTION__,
	    //            __LINE__);

	    // if (dev->otdr_cache[0] == DATA_FLAG) {
	    if (get_cache(dev)[0] == DATA_FLAG) {
		find_23 = 1;
		goto _SerialRead;
	    }

	    // _read_otdr_1(
	    // 		dev,
	    // 		(unsigned char *)(dev->otdr_cache),
	    // 		1);

	    // _read_otdr_1(
	    // 		dev,
	    // 		(unsigned char *)(get_cache(dev)),
	    // 		1);
	}
    }

_SerialRead:;
    // if (find_23 == 0) {
    // 	ENV_PRINT_E(
    // 			"otdr data errr: can't find flag 'DATA_FLAG' (0-100 byte) %2.2x %2.2x %2.2x %2.2x\r\n",
    // 			*(get_cache(dev) + 0),
    // 			*(get_cache(dev) + 1),
    // 			*(get_cache(dev) + 2),
    // 			*(get_cache(dev) + 3));
    // 	mutex_unlock(&dev->mutex);
    // 	printf("%s %d\r\n", __FUNCTION__, __LINE__);
    // 	return -1;
    // }
    mutex_unlock(&dev->mutex);
    // printf("%s %d\r\n", __FUNCTION__, __LINE__);

    /*
    步骤2：读取后面的所有数据
    FPGA数据发送计数器未清0，可能导致不响应之后的数据，解决方法：
    1、otdr_cache长度最好远大于FPGA返回长度，保证把FPGA读空，后面的数据是全0x00或0xff。
    2、每次和FPGA握手时首先度全远大于FPGA返回长度；
    目前只使用方案1，方案2只是验证FPGA有错误。
    后来FPGA做了修改，在每次收到OTDR_START请求后清空计数器；最好的做法是CS上身边沿清除
    */

    // Fix LS2K: 不支持 cs_change = 0,所以必须一次性读取所有数据
    // _read_otdr_serial(dev, (unsigned char *)(dev->otdr_cache), len, 0);
    //_read_otdr_serial(dev, (unsigned char *)(get_cache(dev)), len, 0);


    if (env_dbg_rx) {
	this_dbg("%s() peek receive data", __FUNCTION__);
	PrintfMemory((uint8_t *)rbuf, 16);
    }
    // printf("--------------%s %d\r\n", __FUNCTION__, __LINE__);

    // 拷贝到调用者
    memcpy_char((char *)otdr_data, (char *)(rbuf + 1), len);
    // brief_print_data((unsigned long *)otdr_data, 1000 / 8);
    mutex_unlock(&dev->mutex);


    /*
    数据都在 otdr_data 里，下面的数据double otdr_cache 的锁不再有效
    整个系统最慢的地方就在这里，对数据交换、高Byte清0
    */
    __attribute__((unused)) int swap_err = _otdr_data_swap(otdr_data, len);
    // _print_otdr_data((unsigned long *)otdr_data, len / 4);
    brief_print_data((unsigned long *)otdr_data, len / 4);
#if defined(CONFIG_CHK_OTDR_FLAG) && !defined(CONFIG_USE_CKSUM)
    if (swap_err == -1) {
	return -1;
    }
    return 0;
#else
    if (swap_err == -1) {
	printf("otdr swap error\r\n");
	return -1;
    }
    unsigned long sum = 0;
    if (env_unuse_cksum == 0) {
	sum = __checksum(otdr_data, len);
	if ((unsigned int)(dev->checksum & 0xffffffff) ==
	    (unsigned int)(sum & 0xffffffff))
	{
	    this_dbg("%s() check sum OK\r\n", __FUNCTION__);
	    return 0;
	}
	else {
	    // ENV_PRINT_W
	    printf("check sum error cksum [%lx] otdr [%lx]\n",
	           (long)(dev->checksum),
	           (long)(sum));
	    return -1;
	}
    }
    else {
	// printf("env_unuse_cksum = 1\r\n");
	return 0;
    }
#endif
}


/*
 * 内核没有加补丁，一次只能读取4K
 */
int cb_fpga_read_otdr_data_4k(
	struct fpga_dev *dev,
	unsigned char   *otdr_data,
	unsigned long    len,
	unsigned long   *rlen)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    // assert(dev->otdr_cache != NULL);
    assert(len == 16000 * 4 || len == 32000 * 4 || len == 64000 * 4 ||
           len == 128000 * 4);

    // char *rbuf = dev->otdr_cache;
    // struct otdr_driver_data_tr700 *p = (struct otdr_driver_data_tr700 *)fpga_if_get_driver_data(dev->interface);
    // char *rbuf  = p->otdr_cache;
    char *rbuf = get_cache(dev);
    // char *rbuf = otdr_data;
    /*
     * OTDR 数据格式，第一个0x23开头，后面每 4 byte为1数据点，每数据点
     * 0x23开头 0x23 | 0x23 xx xx xx | 0x23 xx xx xx | 0x23 xx xx xx
     *
     *         otdr_cache 最终存储的内容
     * |    0 byte             32000*4| 4000 |
     * |    OTDR 数据                 | 冗余 |
     * 后面的冗余内容是为了处理OTDR数据偏移而特意多读的
     */
    // do_otdr_test_led(0);
    fpga_if_set_gpio(dev, IO_OTDR_ON_TEST, 0);


    int find_23 = 0;
    this_dbg("%s() search 'DATA_FLAG' \r\n", __FUNCTION__);

    /*
    步骤1：请求数据
    FPGA有BUG，经常返回内容格式“错位”
    本步骤除了_fpga_transfer外，其他都是为了调试查错的
    */
    // 逐个寻找标志字符，
    mutex_lock(&dev->mutex);
    // 这个for循环可以从3改成1
    for (int j = 0; j < 3; j++) {
	/*
	 * 发送请求，这个不能少，只读取 1byte，寻找标志
	 */
	_fpga_transfer(dev,
	               OTDR_ROTDR,
	               &dev->ch,
	               sizeof(dev->ch),
	               //    dev->otdr_cache,
	               get_cache(dev),
	               1);
	/*
	逐个byte读取，在一定范围内寻找otdr数据帧头，
	找到后就连快速读取后面的数据
	*/
#define CHECK_SERIAL (30)  // 在数据头N个字节里寻找标志

	for (int i = 0; i < CHECK_SERIAL; i++) {
	    //            printf("%s() %d\r\n", __FUNCTION__,
	    //            __LINE__);

	    // if (dev->otdr_cache[0] == DATA_FLAG) {
	    if (get_cache(dev)[0] == DATA_FLAG) {
		find_23 = 1;
		goto _SerialRead;
	    }
	    // _read_otdr_1(
	    // 		dev,
	    // 		(unsigned char *)(dev->otdr_cache),
	    // 		1);

	    _read_otdr_1(
		    dev,
		    (unsigned char *)(get_cache(dev)),
		    1);
	}
    }

_SerialRead:;
    if (find_23 == 0) {
	ENV_PRINT_E(
		"otdr data errr: can't find flag 'DATA_FLAG' (0-100 byte) %2.2x %2.2x %2.2x %2.2x\r\n",
		*(get_cache(dev) + 0),
		*(get_cache(dev) + 1),
		*(get_cache(dev) + 2),
		*(get_cache(dev) + 3));
	mutex_unlock(&dev->mutex);
	return -1;
    }


    /*
    步骤2：读取后面的所有数据
    FPGA数据发送计数器未清0，可能导致不响应之后的数据，解决方法：
    1、otdr_cache长度最好远大于FPGA返回长度，保证把FPGA读空，后面的数据是全0x00或0xff。
    2、每次和FPGA握手时首先度全远大于FPGA返回长度；
    目前只使用方案1，方案2只是验证FPGA有错误。
    后来FPGA做了修改，在每次收到OTDR_START请求后清空计数器；最好的做法是CS上身边沿清除
    */

    // Fix LS2K: 不支持 cs_change = 0,所以必须一次性读取所有数据
    // _read_otdr_serial(dev, (unsigned char *)(dev->otdr_cache), len, 0);
    int cache_len = get_cache_len(dev);
    for (int i = 0; i < cache_len;) {
	_read_otdr_serial(dev, (unsigned char *)(get_cache(dev)) + i, 4000, 0);
	i += 4000;
    }


    if (env_dbg_rx) {
	this_dbg("%s() peek receive data", __FUNCTION__);
	PrintfMemory((uint8_t *)rbuf, 16);
    }

    // 拷贝到调用者
    memcpy_char((char *)otdr_data, (char *)(rbuf + 0), len);
    mutex_unlock(&dev->mutex);


    /*
    数据都在 otdr_data 里，下面的数据double otdr_cache 的锁不再有效
    整个系统最慢的地方就在这里，对数据交换、高Byte清0
    */
    __attribute__((unused)) int swap_err = _otdr_data_swap(otdr_data, len);
    // _print_otdr_data((unsigned long *)otdr_data, len / 4);
    brief_print_data((unsigned long *)otdr_data, len / 4);
    extern int env_save_otdr;
    if (env_save_otdr) {
	fpga_save_32bit("/tmp/a-otdr.txt", otdr_data, len);
    }
#if defined(CONFIG_CHK_OTDR_FLAG) && !defined(CONFIG_USE_CKSUM)
    if (swap_err == -1) {
	return -1;
    }
    return 0;
#else
    if (swap_err == -1) {
	printf("otdr swap error\r\n");
	return -1;
    }
    unsigned long sum = 0;
    if (env_unuse_cksum == 0) {
	sum = __checksum(otdr_data, len);
	if ((unsigned int)(dev->checksum & 0xffffffff) ==
	    (unsigned int)(sum & 0xffffffff))
	{
	    this_dbg("%s() check sum OK\r\n", __FUNCTION__);
	    return 0;
	}
	else {
	    ENV_PRINT_W("check sum error cksum [%lx] otdr [%lx]\n",
	                (long)(dev->checksum),
	                (long)(sum));
	    return -1;
	}
    }
    else {
	// printf("env_unuse_cksum = 1\r\n");
	return 0;
    }
#endif
}

static int _fpga_otdr_param(struct fpga_dev *dev, struct fpga_test_param *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct _fpga_test_param_tx tbuf;

    /*
      当 sample_freq 未指定时使用默认采样频率，并计算脉冲宽度编码，
      否则使用自定义采样频率
    */
    if (val->en_hw_pulse == false) {
	tbuf.pulse = _encode_pulse(val);
    }
    else {
	tbuf.pulse = _encode_self_pulse(val);
    }
    if (val->en_hw_dist == false) {
	tbuf.dist = _encode_dist(val);
    }
    else {
	tbuf.dist = _encode_self_dist(val);
    }


    tbuf.laser = _encode_laser(val);
    tbuf.power = _encode_power(val);
    // printf("val->ms = %d\n", val->add_ms);
    tbuf.add_ms = _encode_add_ms(val);
    if (val->en_hw_amp) {
	tbuf.amp = val->hw_amp;
    }
    else {
	tbuf.amp = _encode_amp(val);
    }

    if (val->en_hw_apd_vol) {
	tbuf.apd_vol = val->hw_apd_vol;
    }
    else {
	tbuf.apd_vol = _encode_apd_vol(val);
    }
    tbuf.slot   = _encode_slot(val);
    tbuf.ch     = _encode_ch(val);
    tbuf.unuse1 = 0;
    tbuf.unuse2 = 0;
    tbuf.unuse3 = 0;


    this_dbg("Encode:\r\n");
    this_dbg("    laser             %4.4x\t%d\n", tbuf.laser, tbuf.laser);
    this_dbg("    pulse             %4.4x\t%d\n", tbuf.pulse, tbuf.pulse);
    this_dbg("    dist              %4.4x\t%d\n", tbuf.dist, tbuf.dist);
    this_dbg("    add_ms            %4.4x\t%d\n", tbuf.add_ms, tbuf.add_ms);
    this_dbg("    power             %2.2x\t%d\n", tbuf.power, tbuf.power);
    this_dbg("    amp               %2.2x\t%d\n", tbuf.amp, tbuf.amp);
    this_dbg("    apd_vol           %2.2x\t%d\n", tbuf.apd_vol, tbuf.apd_vol);
    this_dbg("    slot              %2.2x\t%d\n", tbuf.slot, tbuf.slot);
    this_dbg("    ch                %2.2x\t%d\n", tbuf.ch, tbuf.ch);
    this_dbg("    unuse1            %2.2x\n", tbuf.unuse1);
    this_dbg("    unuse2            %2.2x\n", tbuf.unuse2);
    this_dbg("    unuse3            %2.2x\n", tbuf.unuse3);
    dev->ch = tbuf.ch;

    char rbuf[MIN_RX_PACK_SIZE];
    // ENV_PRINT_W("TODO MIN_RX_PACK_SIZE 不是TR600 返回长度");
    unsigned char ack;
    unsigned int  err_times = 0;
    // for (int retry = 0; retry < RETRY; retry++) {
    // 每个循环耗时5.4ms，最多等待1s
    for (int retry = 0; retry < 100; retry++) {
	_fpga_transfer(dev,
	               OTDR_PARAM,
	               (char *)&tbuf,
	               sizeof(struct _fpga_test_param_tx),
	               rbuf,
	               ARRAY_SIZE(rbuf));
	ack = ACK_CODE(rbuf);
	switch (ack) {
	case 0xaa:
	    this_dbg("%s() OK\r\n", __FUNCTION__);
	    // usleep(10000);// FPGA控制光耦
	    goto _AnalyseOther;
	case 0x55:
	    // ENV_PRINT_W("Error\r\n");
	    err_times++;
	    break;
	default:
	    ENV_PRINT_E("unknow\r\n");
	    break;
	}
	usleep(10000);
    }
    if (err_times) {
	ENV_PRINT_W("Error times %d\r\n", err_times);
    }
    ENV_PRINT_E("retry time out\r\n");
    return -1;
_AnalyseOther:;
    if (err_times) {
	ENV_PRINT_W("Error times %d\r\n", err_times);
    }
    /* todo TR700需要返回
     sample_freq 采样频率 MHz
     adopt_pt  采样点数
     */

    // this_dbg("buf 12 %x \n", *(rbuf + 12));
    // *(rbuf + 11)  = 0x11;
    // *(rbuf + 12)  = 0x12;
    // *(rbuf + 13)  = 0x13;
    // *(rbuf + 14)  = 0x14;
    // *(rbuf + 15)  = 0x15;


    // PrintfMemory(rbuf, MIN_RX_PACK_SIZE);

    dev->sample_freq = _decode_freq(rbuf);
    dev->adopt_pt    = _decode_adopt_pt(rbuf);
    this_dbg("Decode:\r\n");
    this_dbg("    sample_freq       %d \n", (int)dev->sample_freq);
    this_dbg("    adopt_pt          %d \n", (int)dev->adopt_pt);
    return 0;
}

#include "interface/protocal-otdr.h"
static int _fpga_otdr_param_tg60(struct fpga_dev *dev, struct fpga_test_param *val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct priv_otdr_data *pdata = dev->interface->private_data;
    // printf("pdata->sw_num %d\r\n", pdata->sw_num);
    struct _fpga_test_param_tx tbuf;

    /*
      当 sample_freq 未指定时使用默认采样频率，并计算脉冲宽度编码，
      否则使用自定义采样频率
    */
    if (val->en_hw_pulse == false) {
	tbuf.pulse = _encode_pulse(val);
    }
    else {
	tbuf.pulse = _encode_self_pulse(val);
    }
    if (val->en_hw_dist == false) {
	tbuf.dist = _encode_dist(val);
    }
    else {
	tbuf.dist = _encode_self_dist(val);
    }


    tbuf.laser = _encode_laser(val);
    tbuf.power = _encode_power(val);
    // printf("val->ms = %d\n", val->add_ms);
    tbuf.add_ms = _encode_add_ms(val);
    if (val->en_hw_amp) {
	tbuf.amp = val->hw_amp;
    }
    else {
	tbuf.amp = _encode_amp(val);
    }

    if (val->en_hw_apd_vol) {
	tbuf.apd_vol = val->hw_apd_vol;
    }
    else {
	tbuf.apd_vol = _encode_apd_vol(val);
    }
    tbuf.slot = _encode_slot(val);
    // tbuf.ch     = (_encode_ch(val) << 6) | (pdata->sw_num);
    tbuf.ch     = ((pdata->sw_fun & 0x3) << 6) | ((_encode_ch(val) + 1) & 0x3f);
    tbuf.unuse1 = 0;
    tbuf.unuse2 = 0;
    tbuf.unuse3 = 0;


    this_dbg("Encode:\r\n");
    this_dbg("    laser             %4.4x\n", tbuf.laser);
    this_dbg("    pulse             %4.4x\n", tbuf.pulse);
    this_dbg("    dist              %4.4x\n", tbuf.dist);
    this_dbg("    add_ms            %4.4x\n", tbuf.add_ms);
    this_dbg("    power             %2.2x\n", tbuf.power);
    this_dbg("    amp               %2.2x\n", tbuf.amp);
    this_dbg("    apd_vol           %2.2x\n", tbuf.apd_vol);
    this_dbg("    slot              %2.2x\n", tbuf.slot);
    this_dbg("    ch                %2.2x\n", tbuf.ch);
    this_dbg("    unuse1            %2.2x\n", tbuf.unuse1);
    this_dbg("    unuse2            %2.2x\n", tbuf.unuse2);
    this_dbg("    unuse3            %2.2x\n", tbuf.unuse3);
    dev->ch = tbuf.ch;

    char rbuf[MIN_RX_PACK_SIZE];
    // ENV_PRINT_W("TODO MIN_RX_PACK_SIZE 不是TR600 返回长度");
    unsigned char ack;
    unsigned int  err_times = 0;
    // for (int retry = 0; retry < RETRY; retry++) {
    // 每个循环耗时5.4ms，最多等待1s
    for (int retry = 0; retry < 100; retry++) {
	_fpga_transfer(dev,
	               OTDR_PARAM,
	               (char *)&tbuf,
	               sizeof(struct _fpga_test_param_tx),
	               rbuf,
	               ARRAY_SIZE(rbuf));
	ack = ACK_CODE(rbuf);
	if (env_ignore_rx) {
	    ack = 0xaa;
	}
	ack = 0xaa;
	switch (ack) {
	case 0xaa:
	    this_dbg("%s() OK\r\n", __FUNCTION__);
	    // usleep(10000);// FPGA控制光耦
	    goto _AnalyseOther;
	case 0x55:
	    // ENV_PRINT_W("Error\r\n");
	    err_times++;
	    break;
	default:
	    ENV_PRINT_E("unknow\r\n");
	    break;
	}
	usleep(10000);
    }
    if (err_times) {
	ENV_PRINT_W("Error times %d\r\n", err_times);
    }
    ENV_PRINT_E("retry time out\r\n");
    return -1;
_AnalyseOther:;
    if (err_times) {
	ENV_PRINT_W("Error times %d\r\n", err_times);
    }
    /* todo TR700需要返回
     sample_freq 采样频率 MHz
     adopt_pt  采样点数
     */

    // this_dbg("buf 12 %x \n", *(rbuf + 12));
    // *(rbuf + 11)  = 0x11;
    // *(rbuf + 12)  = 0x12;
    // *(rbuf + 13)  = 0x13;
    // *(rbuf + 14)  = 0x14;
    // *(rbuf + 15)  = 0x15;


    // PrintfMemory(rbuf, MIN_RX_PACK_SIZE);

    dev->sample_freq = _decode_freq(rbuf);
    dev->adopt_pt    = _decode_adopt_pt(rbuf);
    this_dbg("Decode:\r\n");
    this_dbg("    sample_freq       %d \n", (int)dev->sample_freq);
    this_dbg("    adopt_pt          %d \n", (int)dev->adopt_pt);
    return 0;
}

int cb_fpga_otdr_write_regs(struct fpga_dev *dev, unsigned int base_addr, unsigned int *regs, int len)
{
    // 忽略任何base
    mutex_lock(&dev->mutex);
    int ret = _fpga_otdr_param(dev, (struct fpga_test_param *)regs);
    mutex_unlock(&dev->mutex);

// 如果以后写FPGA的同事能力提高后再真正实现寄存器地址读写
#if 0
	// FPGA只支持某几个地址
	switch(base_addr) {
		case xx:
		fpga_send_data(...);
		break;
	}
	// FPGA支持任何地址
	fpga_send_data(...);
#endif
    return ret;
}


int cb_fpga_otdr_write_regs_tg60(struct fpga_dev *dev, unsigned int base_addr, unsigned int *regs, int len)
{
    mutex_lock(&dev->mutex);
    int                    ret;
    struct priv_otdr_data *pdata = dev->interface->private_data;


    if (base_addr == 0) {
	// 忽略任何base
	ret = _fpga_otdr_param_tg60(dev, (struct fpga_test_param *)regs);
    }
    else if (base_addr == TG60_ADDR_SW_NUM) {
	pdata->sw_num = *regs;
    }
    else if (base_addr == TG60_ADDR_SW_FUN) {
	pdata->sw_fun = *regs;
    }
    mutex_unlock(&dev->mutex);

// 如果以后写FPGA的同事能力提高后再真正实现寄存器地址读写
#if 0
	// FPGA只支持某几个地址
	switch(base_addr) {
		case xx:
		fpga_send_data(...);
		break;
	}
	// FPGA支持任何地址
	fpga_send_data(...);
#endif
    return ret;
}

int cb_fpga_otdr_probe(struct fpga_dev *dev)
{

    struct priv_otdr_data         *pdata_bsp = fpga_if_get_bsp_data(dev->interface);
    struct otdr_driver_data_tr700 *pnew      = malloc(sizeof(struct otdr_driver_data_tr700));

    // printf("\r\nI'm   cb_fpga_otdr_probe\r\n\r\n");
    // printf("pdata_bsp->cache_len %d\r\n", pdata_bsp->cache_len);
    pnew->otdr_cache = (char *)malloc(pdata_bsp->cache_len);
    pnew->cache_len  = pdata_bsp->cache_len;

    fpga_if_set_driver_data(dev->interface, pnew);
    return 0;
}


int cb_fpga_otdr_release(struct fpga_dev *dev)
{
    struct otdr_driver_data_tr700 *pdata_drv = fpga_if_get_driver_data(dev->interface);
    // printf("release\r\n");
    if (pdata_drv->otdr_cache) {
	free(pdata_drv->otdr_cache);
	pdata_drv->otdr_cache = NULL;
    }
    return 0;
}
#include <interface/protocal-otdr.h>
int _fpga_red_laser(struct fpga_dev *dev, int val)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);
    assert(val == OTDR_RL_OFF || val == OTDR_RL_ON || val == OTDR_RL_1HZ || val == OTDR_RL_10HZ);

    char tbuf[2];
    // char rbuf[MIN_RX_PACK_SIZE];
    char rbuf[12];

    tbuf[0] = val;
    tbuf[1] = 0;
    mutex_unlock(&dev->mutex);
    _fpga_transfer(dev, OTDR_REDLASER, tbuf, ARRAY_SIZE(tbuf), rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);

    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
}
int cb_otdr_set_gpio(struct fpga_dev *dev, int io, int val)
{
    switch (io) {
    case IO_OTDR_RED:
	_fpga_red_laser(dev, val);
    case IO_OTDR_ON_TEST:
	// TODO 正在测试LED
	break;
    }
}
